package com.zhima.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhima.constant.QuestionBankRedisConstant;
import com.zhima.dto.QuestionBankDTO;
import com.zhima.dto.UserDTO;
import com.zhima.entity.OjQuestionBank;
import com.zhima.enums.QuestionBankState;
import com.zhima.exception.ErrorCode;
import com.zhima.exception.ResourceNotFoundException;
import com.zhima.exception.ZhimaOjException;
import com.zhima.feignclient.UserFeignClient;
import com.zhima.mapper.OjQuestionBankMapper;
import com.zhima.service.OjQuestionBankService;
import com.zhima.service.OjQuestionBindBankService;
import com.zhima.service.OjQuestionPublishService;
import com.zhima.util.AuthorizationUtil;
import com.zhima.util.PageUtil;
import com.zhima.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhima
 * @since 2023-08-25
 */
@Service
public class OjQuestionBankServiceImpl extends ServiceImpl<OjQuestionBankMapper, OjQuestionBank> implements OjQuestionBankService {

    @Autowired
    private OjQuestionBindBankService ojQuestionBindBankService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private OjQuestionPublishService ojQuestionPublishService;
    @Autowired
    private UserFeignClient userFeignClient;
    @Autowired
    private OjQuestionBankMapper ojQuestionBankMapper;

    @Override
    public String createNewQuestionBank(Long userId, QuestionBankDTO questionBankDTO) {
        OjQuestionBank ojQuestionBank = BeanUtil.copyProperties(questionBankDTO, OjQuestionBank.class);
        ojQuestionBank.setUploaderId(userId);
        ojQuestionBank.setQuestionNum(0);
        if (!save(ojQuestionBank)) {
            throw new ZhimaOjException(ErrorCode.CREATE_QUESTION_BANK_ERROR);
        }
        return ojQuestionBank.getId().toString();
    }

    @Override
    public Page<QuestionBankTableVO> pageQueryQuestionBankBasicInfo(Long userId, Long pageNum, Long pageSize, String keyword) {
        Page<OjQuestionBank> pageResult = page(
                new Page<>(pageNum - 1, pageSize),
                new LambdaQueryWrapper<OjQuestionBank>()
                        .eq(OjQuestionBank::getState, QuestionBankState.PUBLIC)
                        .like(StrUtil.isNotBlank(keyword), OjQuestionBank::getName, keyword)
        );
        List<QuestionBankTableVO> questionBankTableVOS = pageResult.getRecords().stream().map(r -> BeanUtil.copyProperties(r, QuestionBankTableVO.class)).collect(Collectors.toList());
        for (QuestionBankTableVO questionBankTableVO : questionBankTableVOS) {
            questionBankTableVO.setAcNum(stringRedisTemplate.opsForSet().size(String.format(QuestionBankRedisConstant.QUESTION_BANK_USER_PROGRESS, questionBankTableVO.getId(), userId)).intValue());
        }
        return PageUtil.buildPage(pageResult, questionBankTableVOS);
    }

    @Override
    public boolean deleteQuestionBankById(Long userId, Long questionBankId) {
        AuthorizationUtil.isLoginUserResource(userId, getById(questionBankId).getUploaderId());
        return removeById(questionBankId);
    }

    @Override
    public boolean updateQuestionBankBasicInfo(Long userId, QuestionBankDTO questionBankDTO) {
        AuthorizationUtil.isLoginUserResource(userId, getById(questionBankDTO.getId()).getUploaderId());
        return updateById(BeanUtil.copyProperties(questionBankDTO, OjQuestionBank.class));
    }

    @Override
    public QuestionBankShowVO queryQuestionBankDetailById(Long userId, Long questionBankId) {
        OjQuestionBank questionBank = getById(questionBankId);
        if (questionBank == null) {
            throw new ResourceNotFoundException();
        }
        QuestionBankShowVO questionBankVO = BeanUtil.copyProperties(questionBank, QuestionBankShowVO.class);
        // 填充用户头像
        UserDTO uploader = userFeignClient.basicInfoById(questionBank.getUploaderId());
        questionBankVO.setUploaderAvatarUri(uploader.getAvatarUri());
        questionBankVO.setUploaderName(uploader.getUserName());
        // 通过题库id查询题库中的所有题目
        List<QuestionTableVO> questions = ojQuestionBindBankService.queryQuestionsByQuestionBankId(questionBankId);
        questionBankVO.setQuestions(questions);
        // 组装登录用户是否AC
        ojQuestionPublishService.assembleQuestionAc(userId, questions);
        // 填充AC num
        questionBankVO.setAcNum(stringRedisTemplate.opsForSet().size(String.format(QuestionBankRedisConstant.QUESTION_BANK_USER_PROGRESS, questionBank.getId(), userId)).intValue());
        return questionBankVO;
    }

    @Override
    public Page<MineQuestionBankVO> pageQueryMineQuestionBank(Long userId, Long pageNum, Long pageSize) {
        Page<OjQuestionBank> pageResult = page(new Page<>(pageNum, pageSize), new LambdaQueryWrapper<OjQuestionBank>().eq(OjQuestionBank::getUploaderId, userId));
        return PageUtil.buildPage(pageResult, pageResult.getRecords().stream().map(r -> BeanUtil.copyProperties(r, MineQuestionBankVO.class)).collect(Collectors.toList()));
    }

    @Override
    public QuestionBankEditVO queryQuestionBankEditById(Long userId, Long questionBankId) {
        OjQuestionBank questionBank = getById(questionBankId);
        // 检查是否是登录用户的资源
        AuthorizationUtil.isLoginUserResource(userId, questionBank.getUploaderId());
        QuestionBankEditVO questionBankEditVO = BeanUtil.copyProperties(questionBank, QuestionBankEditVO.class);
        questionBankEditVO.setQuestions(ojQuestionBindBankService.queryQuestionBankSimpleQuestion(questionBankId));
        return questionBankEditVO;
    }

    @Override
    public boolean updateQuestionNum(Long questionBankId, boolean increase) {
        return ojQuestionBankMapper.updateQuestionNum(questionBankId, increase);
    }
}
